package com.baijia.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

/**
 * Created by dudu on 16/6/20.
 */
public class SerialNumberUtil {
    private static Logger logger = LoggerFactory.getLogger(SerialNumberUtil.class);

    public static final int MAX = 99999999;
    public static final int COURSE_MAX = 99999999;
    private static final int power = (int) (Math.log(MAX) / Math.log(2));
    //    private static final int allocateStart = MAX - (int)Math.pow(2, power) + 1;
//    private static final int allocateMax = (int)Math.pow(2, power) - 1;
    // 为兼容主站已经录入的十几个机构，保持bitMap和主站一致
    private static final int[] bitMap = new int[] {11, 8, 4, 0, 16, 14, 22, 7, 3, 5, 13, 18, 24, 25, 23, 10, 1, 12, 6, 21, 17, 2, 15, 9, 19, 20};
//    private static final int[] bitMap = mapBit(power - 1);
    private static final int SUFFIX = 9;
    public static final int USER_SUFFIX = 8;
    public static final int ORG_SUFFIX = 9;

    public static long generateNumber(long id, int max) {

        assertId(id, max);

        final long encodedId = encode(id, max);
        final long number = allocateStart(max) + encodedId;
        final long serialNumber = number * 10 + SUFFIX;
        logger.info("generate serialNumber-id:{},encodedId;{},number:{},serailNumber:{}", id, encodedId, number, serialNumber);
        return serialNumber;
    }

    public static long generateNumberNoSuffix(long id, int max) {

        assertId(id, max);

        final long encodedId = encode(id, max);
        final long number = allocateStart(max) + encodedId;
        logger.info("generate serialNumber-id:{},encodedId;{},number:{},serailNumber:{}", id, encodedId, number);
        return number;
    }

    public static long generateNumber(int id, int max, int suffix) {

        assertId(id, max);

        final long encodedId = encode(id, max);
        final long number = allocateStart(max) + encodedId;
        Long serialNum = Long.parseLong(number+"") * 100 + suffix;
//        final int serialNumber = number * 10 + suffix;
//        logger.info("generate serialNumber-id:{},encodedId;{},number:{},serailNumber:{}", id, encodedId, number, serialNumber);
        return serialNum;
    }

    private static int allocateMax(int max) {
        return (int)Math.pow(2, power(max)) - 1;
    }

    private static int power(int max) {
        return (int) (Math.log(max) / Math.log(2));
    }

    private static int allocateStart(int max) {
        return (max - (int)Math.pow(2, power(max)) + 1);
    }

    private static void assertId(long id, int max) {
        int allocateMax = allocateMax(max);
        if(id > allocateMax) {
            throw new RuntimeException("generateNumber by id:"+id+" out of range [1,"+ allocateMax +"] ...");
        }
    }

    private static long encode(long id, int max) {
        long encodedId = 0;

        for (int i = 0; i < power(max); i++) {
            long tmp = (id >> i) & 1;
            encodedId |= tmp << bitMap[i];
        }

        return encodedId;
    }

    private static int[] mapBit(int power) {
        int[] bit = new int[power + 1];
        for (int i = 0; i <= power / 2; i++) {
            if (i % 2 == 0) {
                bit[i] = power - i;
                bit[power - i] = i;
            } else {
                bit[i] = i;
                bit[power - i] = power - i;
            }

        }
        return bit;
    }

    public static void main(String[] args) {
        System.out.println(power(COURSE_MAX));
        System.out.println(Arrays.toString(bitMap));
//        for(int i = 0; i < 1000000; i+=1000) {
//            System.out.println(generateNumberNoSuffix(i, MAX));
////            System.out.println(generateNumber(i, COURSE_MAX));
////            System.out.println(generateNumber(i, COURSE_MAX, 4));
//        }
        System.out.println(generateNumberNoSuffix(65544, MAX));
    }
}
